<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>数据可视化系统 - 9宫格图表展示</title>
<!-- 引入Element UI样式 -->
<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
<!-- 引入ECharts -->
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.1/dist/echarts.min.js"></script>
<!-- 引入Vue -->
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<!-- 引入Element UI组件库 -->
<script src="https://unpkg.com/element-ui/lib/index.js"></script>
<style>
body {
  margin: 0;
  padding: 0;
  font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", Arial, sans-serif;
}
.el-header, .el-footer {
  background: #409EFF;
  color: white;
  line-height: 60px;
  padding: 0 20px !important;
}
.chart-container {
  width: 100%;
  height: 100%;
  border: 1px solid #ebeef5;
  border-radius: 4px;
  padding: 10px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  background: #fff;
}
.loading-text {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100%;
  color: #999;
  font-size: 14px;
}
.system-title {
  font-size: 18px;
  font-weight: bold;
}
</style>
</head>
<body>
<div id="app">
  <el-container style="height: 100vh; flex-direction: column">
    <!-- 头部 -->
    <el-header style="height: 60px;">
      <el-row style="width: 100%">
        <el-col :span="12" class="system-title">企业数据可视化平台</el-col>
        <el-col :span="12" style="text-align: right">
          <el-dropdown @command="handleCommand">
            <span class="el-dropdown-link" style="color: white; cursor: pointer">
              操作菜单<i class="el-icon-arrow-down el-icon--right"></i>
            </span>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item command="refresh"><i class="el-icon-refresh"></i> 刷新数据</el-dropdown-item>
              <el-dropdown-item command="about"><i class="el-icon-info"></i> 关于系统</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </el-col>
      </el-row>
    </el-header>

    <!-- 中间内容 -->
    <el-main style="flex: 1; padding: 0; background: #f5f7fa;">
      <el-row :gutter="20" style="height: 100%; margin: 0; padding: 20px">
        <el-col
          v-for="(item, index) in 9"
          :key="index"
          :span="8"
          style="height: 33.33%; margin-bottom: 20px"
        >
          <div
            :ref="'chart' + index"
            class="chart-container"
          >
            <div v-if="loading[index]" class="loading-text">图表加载中...</div>
          </div>
        </el-col>
      </el-row>
    </el-main>

    <!-- 底部 -->
    <el-footer style="height: 60px;">
      数据可视化系统 © 2023 | 版本 1.0.0
    </el-footer>
  </el-container>
</div>

<script>
new Vue({
  el: '#app',
  data() {
    return {
      charts: [],
      loading: Array(9).fill(true),
      chartTypes: [
        'bar', 'line', 'pie', 'scatter', 'effectScatter',
        'barLineMix', 'barStack', 'rose', 'funnel'
      ],
      localData: []
    };
  },
  mounted() {
    this.initLocalData();
    this.initCharts();
    window.addEventListener('resize', this.resizeCharts);
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.resizeCharts);
  },
  methods: {
    handleCommand(command) {
      if (command === 'refresh') {
        this.refreshAllCharts();
      } else if (command === 'about') {
        this.$message({
          message: '企业数据可视化平台 v1.0 - 9宫格图表展示系统',
          type: 'info'
        });
      }
    },
    initLocalData() {
      // 为每个图表生成不同的模拟数据
      const quarters = ['第一季度', '第二季度', '第三季度', '第四季度'];
      const categories = ['电子产品', '家居用品', '服装', '食品', '其他'];

      for (let i = 0; i < 9; i++) {
        const baseValue = Math.random() * 100 + 50;
        this.localData.push({
          values: [
            Math.round(baseValue),
            Math.round(baseValue * (0.7 + Math.random() * 0.6)),
            Math.round(baseValue * (0.7 + Math.random() * 0.6)),
            Math.round(baseValue * (0.7 + Math.random() * 0.6)),
            Math.round(baseValue * (0.5 + Math.random() * 0.5))
          ],
          categories: categories,
          quarters: quarters
        });
      }
    },
    initCharts() {
      this.$nextTick(() => {
        this.charts = [];
        for (let i = 0; i < 9; i++) {
          const chartDom = this.$refs[`chart${i}`][0];
          const chart = echarts.init(chartDom);
          this.charts.push(chart);
          this.updateChartData(i);
        }
      });
    },
    updateChartData(index) {
      this.loading[index] = true;

      // 模拟数据加载延迟
      setTimeout(() => {
        const data = this.localData[index];
        const option = this.generateChartOption(index, data);
        this.charts[index].setOption(option);
        this.loading[index] = false;
      }, 300);
    },
    generateChartOption(index, data) {
      const chartType = this.chartTypes[index];
      const chartTitles = [
        '年度产品销售统计',
        '用户增长趋势分析',
        '产品市场份额分布',
        '客户满意度调查',
        '营销活动效果评估',
        '部门业绩对比',
        '项目进度统计',
        '区域销售占比',
        '销售转化率分析'
      ];
      const chartTitle = chartTitles[index];

      // 基础配置
      let option = {
        title: {
          text: chartTitle,
          left: 'center',
          textStyle: {
            fontSize: 14,
            fontWeight: 'bold',
            color: '#333'
          },
          subtext: index % 2 === 0 ? '单位：万元' : '单位：个',
          subtextStyle: {
            fontSize: 12,
            color: '#999'
          }
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'shadow'
          }
        },
        legend: {
          data: data.categories.slice(0, 4),
          bottom: 5,
          orient: 'horizontal',
          itemWidth: 12,
          itemHeight: 12,
          textStyle: {
            fontSize: 12
          }
        },
        grid: {
          top: '20%',
          bottom: '15%',
          left: '10%',
          right: '10%',
          containLabel: true
        },
        xAxis: {
          type: 'category',
          data: data.quarters,
          name: '季度',
          axisLabel: {
            interval: 0,
            fontSize: 12
          },
          axisLine: {
            lineStyle: {
              color: '#ddd'
            }
          },
          axisTick: {
            alignWithLabel: true
          }
        },
        yAxis: {
          type: 'value',
          name: '数值',
          axisLine: {
            show: true,
            lineStyle: {
              color: '#ddd'
            }
          },
          splitLine: {
            lineStyle: {
              type: 'dashed'
            }
          }
        },
        series: []
      };

      // 颜色方案
      const colorMap = {
        'bar': '#409EFF',
        'line': '#67C23A',
        'pie': ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C', '#909399'],
        'scatter': '#E6A23C',
        'effectScatter': '#F56C6C',
        'barLineMix': ['#409EFF', '#67C23A'],
        'barStack': ['#409EFF', '#E6A23C'],
        'rose': ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C'],
        'funnel': ['#409EFF', '#67C23A', '#E6A23C', '#F56C6C']
      };

      // 根据不同类型生成系列数据
      switch (chartType) {
        case 'bar':
          option.series.push({
            name: '销售额',
            type: chartType,
            barWidth: '40%',
            data: data.values.slice(0, 4),
            itemStyle: {
              color: colorMap[chartType],
              borderRadius: [4, 4, 0, 0]
            },
            label: {
              show: true,
              position: 'top',
              fontSize: 12
            }
          });
          break;

        case 'line':
          option.series.push({
            name: '用户数',
            type: chartType,
            data: data.values.slice(0, 4),
            smooth: true,
            symbol: 'circle',
            symbolSize: 8,
            lineStyle: {
              width: 3,
              color: colorMap[chartType]
            },
            itemStyle: {
              color: colorMap[chartType],
              borderWidth: 2,
              borderColor: '#fff'
            },
            label: {
              show: true,
              position: 'top',
              fontSize: 12
            },
            areaStyle: {
              color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
                { offset: 0, color: 'rgba(103, 194, 58, 0.3)' },
                { offset: 1, color: 'rgba(103, 194, 58, 0.1)' }
              ])
            }
          });
          break;

        case 'pie':
          option = {
            title: {
              text: chartTitle,
              left: 'center',
              textStyle: {
                fontSize: 14,
                fontWeight: 'bold',
                color: '#333'
              },
              subtext: '占比分析',
              subtextStyle: {
                fontSize: 12,
                color: '#999'
              }
            },
            tooltip: {
              trigger: 'item',
              formatter: '{a} <br/>{b}: {c} ({d}%)'
            },
            legend: {
              data: data.categories,
              bottom: 5,
              orient: 'horizontal',
              itemWidth: 12,
              itemHeight: 12,
              textStyle: {
                fontSize: 12
              }
            },
            series: [{
              name: '市场份额',
              type: chartType,
              radius: ['40%', '70%'],
              center: ['50%', '45%'],
              avoidLabelOverlap: true,
              label: {
                show: true,
                formatter: '{b}: {d}%',
                fontSize: 12
              },
              labelLine: {
                length: 15,
                length2: 10
              },
              data: data.values.map((val, i) => ({
                value: val,
                name: data.categories[i]
              })),
              itemStyle: {
                color: function(params) {
                  return colorMap[chartType][params.dataIndex % colorMap[chartType].length];
                },
                borderRadius: 4,
                borderWidth: 1,
                borderColor: '#fff'
              },
              emphasis: {
                itemStyle: {
                  shadowBlur: 10,
                  shadowOffsetX: 0,
                  shadowColor: 'rgba(0, 0, 0, 0.5)'
                }
              }
            }]
          };
          break;

        case 'scatter':
          option.series.push({
            name: '数据点',
            type: chartType,
            symbolSize: function(val) {
              return val[1] / 3;
            },
            data: data.values.map((val, i) => [i, val]),
            itemStyle: {
              color: colorMap[chartType],
              borderWidth: 1,
              borderColor: '#fff'
            },
            label: {
              show: true,
              formatter: function(params) {
                return data.categories[params.dataIndex];
              },
              fontSize: 12,
              position: 'top'
            }
          });
          break;

        case 'effectScatter':
          option.series.push({
            name: '重点数据',
            type: chartType,
            showEffectOn: 'render',
            rippleEffect: {
              brushType: 'stroke',
              scale: 3
            },
            symbolSize: function(val) {
              return val[1] / 3;
            },
            data: data.values.map((val, i) => ({
              value: [i, val],
              name: data.categories[i]
            })),
            itemStyle: {
              color: colorMap[chartType],
              shadowBlur: 10,
              shadowColor: colorMap[chartType]
            },
            label: {
              show: true,
              formatter: '{b}',
              fontSize: 12,
              position: 'top'
            }
          });
          break;

        case 'barLineMix':
          option.series.push({
            name: '销售额',
            type: 'bar',
            barWidth: '40%',
            data: data.values.slice(0, 4),
            itemStyle: {
              color: colorMap[chartType][0],
              borderRadius: [4, 4, 0, 0]
            },
            label: {
              show: true,
              position: 'top',
              fontSize: 12
            }
          }, {
            name: '同比增长',
            type: 'line',
            data: data.values.slice(0, 4).map(val => val * 1.2),
            smooth: true,
            symbol: 'diamond',
            symbolSize: 10,
            lineStyle: {
              width: 3,
              color: colorMap[chartType][1]
            },
            itemStyle: {
              color: colorMap[chartType][1],
              borderWidth: 2,
              borderColor: '#fff'
            },
            label: {
              show: true,
              position: 'top',
              fontSize: 12,
              formatter: '+20%'
            }
          });
          break;

        case 'barStack':
          option.series.push({
            name: '线上销售',
            type: 'bar',
            stack: '总量',
            barWidth: '40%',
            data: data.values.slice(0, 4),
            itemStyle: {
              color: colorMap[chartType][0],
              borderRadius: [4, 4, 0, 0]
            },
            label: {
              show: true,
              position: 'inside',
              fontSize: 12
            }
          }, {
            name: '线下销售',
            type: 'bar',
            stack: '总量',
            barWidth: '40%',
            data: data.values.slice(0, 4).map(val => val * 0.8),
            itemStyle: {
              color: colorMap[chartType][1],
              borderRadius: [4, 4, 0, 0]
            },
            label: {
              show: true,
              position: 'inside',
              fontSize: 12
            }
          });
          break;

        case 'rose':
          option = {
            title: {
              text: chartTitle,
              left: 'center',
              textStyle: {
                fontSize: 14,
                fontWeight: 'bold',
                color: '#333'
              },
              subtext: '区域对比',
              subtextStyle: {
                fontSize: 12,
                color: '#999'
              }
            },
            tooltip: {
              trigger: 'item',
              formatter: '{a} <br/>{b}: {c} ({d}%)'
            },
            legend: {
              data: data.categories,
              bottom: 5,
              orient: 'horizontal',
              itemWidth: 12,
              itemHeight: 12,
              textStyle: {
                fontSize: 12
              }
            },
            polar: {},
            angleAxis: {
              type: 'category',
              data: data.categories,
              axisLabel: {
                fontSize: 12
              }
            },
            radiusAxis: {
              axisLabel: {
                fontSize: 12
              }
            },
            series: [{
              name: '销售数据',
              type: 'rose',
              radius: ['20%', '80%'],
              center: ['50%', '45%'],
              data: data.values.map((val, i) => ({
                value: val,
                name: data.categories[i]
              })),
              label: {
                show: true,
                formatter: '{b}: {c}',
                fontSize: 12
              },
              itemStyle: {
                color: function(params) {
                  return colorMap[chartType][params.dataIndex % colorMap[chartType].length];
                },
                borderRadius: 4
              },
              emphasis: {
                itemStyle: {
                  shadowBlur: 10,
                  shadowOffsetX: 0,
                  shadowColor: 'rgba(0, 0, 0, 0.5)'
                }
              }
            }]
          };
          break;

        case 'funnel':
          option = {
            title: {
              text: chartTitle,
              left: 'center',
              textStyle: {
                fontSize: 14,
                fontWeight: 'bold',
                color: '#333'
              },
              subtext: '转化率分析',
              subtextStyle: {
                fontSize: 12,
                color: '#999'
              }
            },
            tooltip: {
              trigger: 'item',
              formatter: '{a} <br/>{b}: {c} ({d}%)'
            },
            legend: {
              data: data.categories,
              bottom: 5,
              orient: 'horizontal',
              itemWidth: 12,
              itemHeight: 12,
              textStyle: {
                fontSize: 12
              }
            },
            series: [{
              name: '转化率',
              type: 'funnel',
              left: '15%',
              top: '15%',
              bottom: '15%',
              width: '70%',
              min: 0,
              max: 100,
              minSize: '0%',
              maxSize: '100%',
              sort: 'descending',
              gap: 2,
              label: {
                show: true,
                position: 'inside',
                formatter: '{b}: {c}%',
                fontSize: 12
              },
              labelLine: {
                length: 10,
                lineStyle: {
                  width: 1,
                  type: 'solid'
                }
              },
              itemStyle: {
                borderColor: '#fff',
                borderWidth: 1,
                color: function(params) {
                  return colorMap[chartType][params.dataIndex % colorMap[chartType].length];
                }
              },
              emphasis: {
                label: {
                  fontSize: 14
                }
              },
              data: data.values.map((val, i) => ({
                value: val,
                name: data.categories[i]
              }))
            }]
          };
          break;
      }

      return option;
    },
    resizeCharts() {
      this.charts.forEach(chart => chart.resize());
    },
    refreshAllCharts() {
      // 重新生成所有数据
      this.localData = [];
      this.initLocalData();

      // 更新所有图表
      for (let i = 0; i < 9; i++) {
        this.loading[i] = true;
        this.updateChartData(i);
      }

      this.$message({
        message: '数据已刷新',
        type: 'success',
        duration: 1000
      });
    }
  }
});
</script>
</body>
</html>